package com.template.project.config;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.IOException;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * OkHttp 配置类
 * 配置SSL安全，禁用弱协议，并集成RestTemplate
 *
 * @author xs
 */
@Slf4j
@Configuration
public class OkHttpConfig {
    @Resource
    private AllowedHostsConfig allowedHostsConfig;

    @Bean
    @ConditionalOnMissingBean
    public OkHttpClient okHttpClient() {
        // 使用默认的 TrustManagerFactory 创建一个 TrustManager
        TrustManagerFactory trustManagerFactory;
        try {
            trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init((KeyStore) null);
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize TrustManagerFactory", e);
        }

        X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];

        SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{trustManager}, new java.security.SecureRandom());
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize SSLContext", e);
        }

        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        return new OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory, trustManager)
                .hostnameVerifier((hostname, session) -> allowedHostsConfig.getHosts().contains(hostname))
                .connectionSpecs(Arrays.asList(
                        new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                                .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3)
                                .allEnabledCipherSuites()
                                .build(),
                        ConnectionSpec.CLEARTEXT))
                .connectTimeout(15, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool(100, 5, TimeUnit.MINUTES))
                .retryOnConnectionFailure(true)
                .addInterceptor(new LoggingInterceptor())
                .addInterceptor(new ErrorHandlingInterceptor())
                .build();
    }

    // 日志拦截器
    static class LoggingInterceptor implements Interceptor {
        @NotNull
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long startTime = System.nanoTime();
            log.debug("Sending request {} on {} with headers {}",
                    request.url(), chain.connection(), request.headers());
            Response response = chain.proceed(request);
            long endTime = System.nanoTime();
            log.debug("Received response for {} in {}ms with headers {}",
                    response.request().url(), (endTime - startTime) / 1e6d, response.headers());
            return response;
        }
    }

    // 错误处理拦截器
    static class ErrorHandlingInterceptor implements Interceptor {
        @NotNull
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            if (!response.isSuccessful()) {
                log.error("Unexpected response code {} for request {}",
                        response.code(), response.request().url());
                throw new IOException("Unexpected code " + response);
            }
            return response;
        }
    }

    // RestTemplate集成OkHttpClient
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient()))
                .build();
    }

    @Getter
    @Component
    @ConfigurationProperties(prefix = "request")
    public static class AllowedHostsConfig {

        private List<String> hosts;

        public void setHosts(List<String> hosts) {
            this.hosts = hosts;
        }
    }
}
